﻿
using System;
using System.Collections.Generic;
using System.Linq;


namespace Boilen.Primitives.Members {

    /// <summary>
    /// Writes a named block of code enclosed.
    /// </summary>
    public sealed class BlockMember : Member {

        private readonly string contentValue_;
        private readonly Action<ICodeWriter> content_;
        private readonly List<Guard> guards_ = new List<Guard>( );


        /// <inheritdoc/>
        public override Extensions UsedExtensions {
            get { return this.Guards.Any( ) ? Extensions.Validation : Extensions.None; }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the block should write it's name before the body.
        /// </summary>
        public bool WriteName { get; set; }

        /// <summary>
        /// Gets or sets a writer for content preceding any block guards.
        /// </summary>
        public Action<ICodeWriter> PreContent { get; set; }

        /// <summary>
        /// Gets the content string for the body of the block.
        /// </summary>
        public string ContentValue { get { return this.contentValue_; } }

        /// <summary>
        /// Gets the content writer for the body of the block.
        /// </summary>
        public Action<ICodeWriter> Content { get { return this.content_; } }

        /// <summary>
        /// Gets the collections of guards for the member.
        /// </summary>
        public IEnumerable<Guard> Guards { get { return this.guards_.AsEnumerable( ); } }


        /// <summary>
        /// Initializes a new <see cref="BlockMember"/> instance.
        /// </summary>
        /// <param name="name">The name of the block.</param>
        /// <param name="content">The content for the body of the block.</param>
        public BlockMember( string name, string content )
            : base( name ) {
            this.contentValue_ = content ?? "";
            this.content_ = null;
        }

        /// <summary>
        /// Initializes a new <see cref="BlockMember"/> instance.
        /// </summary>
        /// <param name="name">The name of the block.</param>
        /// <param name="content">The content writer for the body of the block.</param>
        public BlockMember( string name, Action<ICodeWriter> content )
            : base( name ) {
            Ensure.NotNull( content );

            this.contentValue_ = "";
            this.content_ = content;
        }


        /// <summary>
        /// Adds guards to the member.
        /// </summary>
        public BlockMember AddGuards( IEnumerable<Guard> newGuards ) {
            this.guards_.AddRange( newGuards );
            return this;
        }


        /// <inheritdoc/>
        protected override void WriteCore( ICodeWriter writer ) {
            if( this.PreContent == null && this.Content == null && !this.Guards.Any( ) ) {
                if( this.WriteName )
                    writer.Write( this.Name + " " );
                writer.Write( "{ " );
                if( this.ContentValue.Length > 0 )
                    writer.Write( this.ContentValue + " " );
                writer.WriteLine( "}" );
            }
            else {
                if( this.WriteName )
                    writer.WriteLine( this.Name );

                using( Enclose.Braces( writer ) ) {
                    if( this.PreContent != null ) {
                        this.PreContent( writer );
                        writer.WriteLine( );
                    }

                    Guard.WriteGuards( writer, this.Guards );

                    if( this.ContentValue.Length > 0 )
                        writer.WriteLine( this.ContentValue );

                    if( this.Content != null )
                        this.Content( writer );
                }
            }
        }

    }

}
